/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.prep;

import java.util.List;

import br.ufmg.dees.insane.model.geo.GCurve;
import br.ufmg.dees.insane.model.geo.GPoint;
import br.ufmg.dees.insane.model.geo.GRegion;

public class BilinearToSerenQ extends Bilinear{
	
//*****************************************************************************
	
	public BilinearToSerenQ(int ln, int le, int nppe, GRegion rg){
		this.lastNode = ln;
		this.lastElement = le;
		this.nPointsPerElement = nppe;
		this.region = rg;
		
		this.mapNodes();
		this.conectivite();
	}
	
//*****************************************************************************
	
	private void mapNodes(){
		int nPointsElementSide = nPointsPerElement/4 + 1;
		
		List curves = this.region.getCurves();
		GPoint[] curve1 = ((GCurve)curves.get(0)).getDiscrete((GPoint)region.getFirstPoint());
		GPoint[] curve2 = ((GCurve)curves.get(1)).getDiscrete(curve1[curve1.length-1]);
		GPoint[] curve3 = ((GCurve)curves.get(2)).getDiscrete(curve2[curve2.length-1]);
		GPoint[] curve4 = ((GCurve)curves.get(3)).getDiscrete(curve3[curve3.length-1]);
		
		int nPoints1 = curve1.length;
		int nPoints2 = curve2.length;
		
		double x, y;
		int ci, cj;
		for (int i = 0; i < nPoints2; i++) {
			ci = nPoints2-(i+1);
			double v = (double)i/(nPoints2-1);
			for (int j = 0; j < nPoints1; j++) {
				if ( i%(nPointsElementSide-1)==0 || j%(nPointsElementSide-1)==0 ) {
					cj = nPoints1-(j+1);
					lastNode++;
					double u = (double)j/(nPoints1-1);
					x =  (1.0-v)*curve1[ j].getX()+v*curve3[cj].getX()
						+(1.0-u)*curve4[ci].getX()+u*curve2[ i].getX()
						-(1.0-u)*(1.0-v)*curve1[0].getX()
						-u*(1.0-v)*curve1[nPoints1-1].getX()
						-(1.0-u)*v*curve3[nPoints1-1].getX()
						-u*v*curve3[0].getX();
					y =  (1.0-v)*curve1[ j].getY()+v*curve3[cj].getY()
						+(1.0-u)*curve4[ci].getY()+u*curve2[ i].getY()
						-(1.0-u)*(1.0-v)*curve1[0].getY()
						-u*(1.0-v)*curve1[nPoints1-1].getY()
						-(1.0-u)*v*curve3[nPoints1-1].getY()
						-u*v*curve3[0].getY();
					MapNode mn = new MapNode(x, y, lastNode);
					if ( i==0 || j==0 || i==(nPoints2-1) || j==(nPoints1-1) ) {
						mn.setBoundary( true );
					}
					this.nodes.add(mn);
				}
			}
		}
	}
	
//*****************************************************************************
	
	private void conectivite(){
		List curves = this.region.getCurves();
		GPoint[] curve1 = ((GCurve)curves.get(0)).getDiscrete((GPoint)region.getFirstPoint());
		GPoint[] curve2 = ((GCurve)curves.get(1)).getDiscrete(curve1[curve1.length-1]);
		int nPoints1 = curve1.length;
		int nPoints2 = curve2.length;
		int nPointsElementSide = nPointsPerElement/4 + 1;
		
		int nElements1 = (nPoints1 - 1)/(nPointsElementSide - 1);
		int nElements2 = (nPoints2 - 1)/(nPointsElementSide - 1);
		int element = this.lastElement;
		MapNode[] conec = new MapNode[4*(nPointsElementSide-1)];
		for (int i = 0; i < nElements2; i++) {
			for (int j = 0; j < nElements1; j++) {
				element++;
				int no = -1;
				//	algoritimo para gerar elemento no sentido anti-horario
				// lado superior
				for (int k = nPointsElementSide; k >= 1; k--) {
					no++;
					conec[no] = (MapNode)nodes.get( i*(nPoints1+(nElements1+1)*(nPointsElementSide-2)) + j*(nPointsElementSide-1) + k - 1 );
				}
				// lado esquerdo
				for (int k = 1; k <= (nPointsElementSide-2); k++) {
					no++;
					conec[no] = (MapNode)nodes.get( (i+1)*(nPoints1) + i*(nElements1+1)*(nPointsElementSide-2) + (k-1)*(nElements1+1) + (j+1) - 1 );
				}
				// lado inferior
				for (int k = 1; k <= nPointsElementSide; k++) {
					no++;
					conec[no] = (MapNode)nodes.get( (i+1)*(nPoints1) + (i+1)*(nElements1+1)*(nPointsElementSide-2) + j*(nPointsElementSide-1) + k - 1 );
				}
				// lado direito
				for (int k = (nPointsElementSide-2); k >= 1; k--) {
					no++;
					conec[no] = (MapNode)nodes.get( (i+1)*(nPoints1) + i*(nPointsElementSide-2)*(nElements1+1) + (k-1)*(nElements1+1) + (j+2) - 1 );
				}
				MapElement me = new MapElement(element, conec, conec);
				me.setType('Q','S');
				this.elements.add(me);
			}
		}
	}
		
//*****************************************************************************
}

